/**
 * 
 */
package com.wayoos.wap.server;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.InputStream;
import java.lang.management.ManagementFactory;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import com.wayoos.launcher.Bootstrap;
import com.wayoos.launcher.Daemon;
import com.wayoos.wap.api.Application;
import com.wayoos.wap.api.ApplicationContextAware;
import com.wayoos.wap.api.ApplicationLifecycle;
import com.wayoos.wap.api.component.WapComponent;
import com.wayoos.wap.api.context.WapContextImpl;
import com.wayoos.wap.server.watchdog.WatchDogEvent;
import com.wayoos.wap.server.watchdog.WatchDogEventHandler;
import com.wayoos.wap.server.watchdog.WatchDogHTTPServer;

/**
 * @author steph
 * 
 */
public class WapServer implements WatchDogEventHandler {

	public static final String WAP_CLASS_FILE = "APP-INF/app.properties";

	public static final String APPLICATION_CLASS_KEY = "componentClass";

	public static final String DEFAULT_APP = "registry";

	private Application application;

	private WatchDogHTTPServer watchDogHTTPServer;

	private Class<WapComponent> findWapComponentClass(ClassLoader classLoader) throws IOException,
			ClassNotFoundException {

		Properties properties = new Properties();

		InputStream is = classLoader.getResourceAsStream(WAP_CLASS_FILE);

		if (is != null) {

			properties.load(is);

			String className = (String) properties.get(APPLICATION_CLASS_KEY);

			Class<?> mainClass = classLoader.loadClass(className);

			// TODO throw exception if not implement Application
			return (Class<WapComponent>) mainClass;
		}

		return null;
	}

	public void cmd(String[] args) {
		if (args.length <= 0) {
			if (Daemon.isDaemonized()) {
				start(DEFAULT_APP);
			} else {
				printHelp();
			}
		} else if (args[0].equals("start")) {
			if (args.length >= 2) {
				start(args[1]);
			} else {
				start(DEFAULT_APP);
			}
		} else if (args[0].equals("stop")) {
			if (args.length >= 2) {
				stop(args[1]);
			} else {
				stop(DEFAULT_APP);
			}
		} else {
			printHelp();
		}
	}

	private Map<String, Class<WapComponent>> findWapComponentsClass() {

		// first find in the current classloader

		// if not find deployed component and find it by name

		// for each create a new URLClassLoader and mybe put it in the cache and
		// make an autorefresh

		return null;
	}

	public void stop(String app) {
		System.out.println("---------------");
		System.out.println("WapServer: stop " + app);
		System.out.println("---------------");

		// read in var dir the watchdog url and stop it

		// for local host use a normal url

		// for remote add a secure path

		try {
			URL url = new URL("http://localhost:6080/stop");

			URLConnection connection = url.openConnection();
			connection.connect();
			// connection

			// HttpURLConnection connection = HttpURLConnection.

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public void start(String app) {

		System.out.println("----------------");
		System.out.println("WapServer: start " + app);
		System.out.println("IsDaemonized: " + Daemon.isDaemonized());
		System.out.println("pidName: " + ManagementFactory.getRuntimeMXBean().getName());
		System.out.println("----------------");

		WapComponent component = null;

		try {
			Class<WapComponent> componentClass = findWapComponentClass(Thread.currentThread()
					.getContextClassLoader());

			if (componentClass == null) {
				// create new classloader
				File baseDir = Bootstrap.findBaseDir();

				File appBaseDir = new File(baseDir, "apps" + File.separator + app);

				// check if the app is deployed
				deployApp(app);

				ClassLoader classLoader = getClassLoader(appBaseDir, Thread.currentThread()
						.getContextClassLoader());
				componentClass = findWapComponentClass(classLoader);

				Thread.currentThread().setContextClassLoader(classLoader);
			}

			component = componentClass.newInstance();

			// start the watchdog

			// start the application

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		if (Daemon.isDaemonized()) {

			application = component.getApplication();

			startWatchdog();

			if (application instanceof ApplicationContextAware) {
				WapContextImpl context = new WapContextImpl();

				((ApplicationContextAware) application).setContext(context);
			}

			if (application instanceof ApplicationLifecycle) {
				((ApplicationLifecycle) application).start();
			}

		} else {
			// instanciate the wap application to find the demonized info

			// find component with app name

			// component

			new Daemon().args("start", app).daemonize();
		}
	}

	private void startWatchdog() {

		try {
			watchDogHTTPServer = new WatchDogHTTPServer(this, "text/plain", 6080);
			watchDogHTTPServer.start();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public void stop() {
		System.out.println("Wap Server stop.");

		if (application instanceof ApplicationLifecycle) {
			((ApplicationLifecycle) application).stop();
		}

		watchDogHTTPServer.stop();
		// TODO stop the process
		// 1 go to registry and with REST cmd stop the jvm

		// 2 find the pid but on a distributed env ???

		// 3 execute a REST request on the registry en the registry will stop it
		// with pid. It's ok if we have an registry on all server ?

		// 4 stop it with jmx
	}

	public void printHelp() {
		System.out.println("Wap server commands: ");
		System.out.println("start [app]");
		System.out.println("stop [app]");
	}

	public static void main(String[] args) {
		new WapServer().cmd(args);
	}

	private ClassLoader getClassLoader(File baseDirFile, ClassLoader currentClassLoader)
			throws MalformedURLException {

		List<URL> urls = new ArrayList<URL>();

		URL confDirUrl = new URL("file:" + baseDirFile.getAbsolutePath() + "/conf/");

		urls.add(confDirUrl);

		// find all jar in lib dir
		File libDir = new File(baseDirFile, "lib");
		if (libDir.exists()) {
			File[] jarsList = libDir.listFiles(new FileFilter() {

				@Override
				public boolean accept(File pathname) {
					if (pathname.getAbsolutePath().endsWith(".jar")) {
						return true;
					}
					return false;
				}
			});

			for (File jarFile : jarsList) {
				urls.add(jarFile.toURI().toURL());
			}
		}
		URLClassLoader classLoader = new URLClassLoader(urls.toArray(new URL[0]),
				currentClassLoader);

		return classLoader;
	}

	private void deployApp(String app) {
		File baseDir = Bootstrap.findBaseDir();

		File appsDir = new File(baseDir, "apps");

		File appBaseDir = new File(appsDir, app);

		if (!appBaseDir.exists()) {
			File appBundleFile = new File(appsDir, app + ".zip");

			UnzipUtils.unzipMyZip(appBundleFile, appBaseDir);
		}
	}

	@Override
	public void onEvent(WatchDogEvent event) {
		// TODO Auto-generated method stub
		stop();
	}

}
